/*****************************
 *@file: BaseCharacterPhysics
 *@author: 陈吕唐
 *@desc: 基础角色碰撞物理
 *@date: 2024-03-18	09:34
 *****************************/
import { _decorator, Collider2D, Contact2DType, IPhysics2DContact, RigidBody2D, warn } from 'cc';
import { BaseCharacter } from './BaseCharacter';
import GameUtils from './GameUtils';
import { PhysicsEnum } from './PhysicsEnum';
const { ccclass, property } = _decorator;

@ccclass('BaseCharacterPhysics')
export class BaseCharacterPhysics extends BaseCharacter {
    /****************************************************************************************************************
     *Readonly 常量
     ****************************************************************************************************************/
    /****************************************************************************************************************
     *Property 定义变量
     ****************************************************************************************************************/
    /***************************************************************
    *PropertyUI 引用的控件
    ***************************************************************/
    @property({ group: { name: 'BOX2D', id: '1' }, type: RigidBody2D, tooltip: `当前战斗单位刚体(默认从当前节点查找)` })
    protected body: RigidBody2D = undefined!

    @property({ group: { name: 'BOX2D', id: '1' }, type: Collider2D, tooltip: `当前碰撞实体形状(默认从当前节点查找)` })
    private bodyCollider: Collider2D = null;

    @property({ group: { name: 'BOX2D', id: '1' }, type: Collider2D, override: true, tooltip: `当前感应范围形状(默认从当前节点查找)` })
    protected sensorCollider: Collider2D = null;
    /****************************************************************************************************************
     * Lifecycle 生命周期相关方法
     ****************************************************************************************************************/
    protected onLoad(): void {
        super.onLoad();
        if (!this.body) {
            this.body = this.node.getComponent(RigidBody2D);
        }

        let colliders = this.node.getComponents(Collider2D);
        if (!this.bodyCollider) {
            this.bodyCollider = colliders.find((c) => c.tag === PhysicsEnum.ColliderTagGroup.BODY);
        }

        if (this.bodyCollider) {
            this.addBodyListener(this.bodyCollider);
        }


        if (!this.sensorCollider) {
            this.sensorCollider = colliders.find((c) => c.tag === PhysicsEnum.ColliderTagGroup.SENSOR);
        }

        if (this.sensorCollider) {
            this.addSensorListener(this.sensorCollider);
        }
    }
    /****************************************************************************************************************
     * Public 公有方法
     ****************************************************************************************************************/
    /**
     * 进入感应范围时调用
     * @param selfCollider 
     * @param otherCollider 
     * @param contact 
     */
    private onBeginSensorContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        // 只在两个碰撞体开始接触时被调用一次
        let character = GameUtils.getCharacterByCollider(otherCollider);
        if (character) {
            this.onSensor(character);
        }
    }

    /**
     * 退出感应范围时调用
     * @param selfCollider 
     * @param otherCollider 
     * @param contact 
     */
    private onEndSensorContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        // 只在两个碰撞体结束接触时被调用一次
    }

    /**
     * 碰撞到实体时候调用
     * @param selfCollider 
     * @param otherCollider 
     * @param contact 
     */
    private onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        // 只在两个碰撞体开始接触时被调用一次 group值是 2^碰撞矩阵索引
        switch (otherCollider.group) {
            case PhysicsEnum.PhysicsGroup.BORDER:
                this.onBorder();
                break;
            default:
                break;
        }

        let character = GameUtils.getCharacterByCollider(otherCollider);
        if (character) {
            this.onHit(character);
        }
    }

    /**
     * 碰撞到实体分开时候调用
     * @param selfCollider 
     * @param otherCollider 
     * @param contact 
     */
    private onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        // 只在两个碰撞体结束接触时被调用一次
        console.log('onEndContact');
    }
    /****************************************************************************************************************
     * private 私有方法
     ****************************************************************************************************************/

    /**
     * 进入感应范围
     * @param character 
     */
    protected onSensor(character: BaseCharacter) {

    }

    /**
     * 撞击到对象
     * @param character 
     */
    protected onHit(character: BaseCharacter) {

    }

    /**
     * 碰到边界
     */
    protected onBorder() {

    }

    /**
     * 添加碰撞实体监听
     * @param collider 
     * @returns 
     */
    private addBodyListener(collider: Collider2D = this.bodyCollider) {
        if (!collider) {
            warn('collider is null');
            return;
        }


        if (!collider.hasEventListener(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this)) {
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
        }
        if (!collider.hasEventListener(Contact2DType.END_CONTACT, this.onEndContact, this)) {
            collider.on(Contact2DType.END_CONTACT, this.onEndContact, this);
        }
    }

    /**
     * 添加感应范围监听
     * @param collider 
     * @returns 
     */
    private addSensorListener(collider: Collider2D = this.bodyCollider) {
        if (!collider) {
            warn('collider is null');
            return;
        }

        if (!collider.hasEventListener(Contact2DType.BEGIN_CONTACT, this.onBeginSensorContact, this)) {
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginSensorContact, this);
        }
        if (!collider.hasEventListener(Contact2DType.END_CONTACT, this.onEndSensorContact, this)) {
            collider.on(Contact2DType.END_CONTACT, this.onEndSensorContact, this);
        }
    }
    /****************************************************************************************************************
     * Property Get && Set 属性的 get && set 函数
     ****************************************************************************************************************/

}


